using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using XDL.Framework.Particles;
using XDL.Framework.Screens;
using System.IO;
using XDL.Framework;
using XDL.Framework.Weapons;

namespace JumpNFight
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class JumpNFightGame : 
        Microsoft.Xna.Framework.Game
    {
        RenderTarget2D m_renderTexture;
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        AudioManager audioManager;
        Simulation.World m_world;
        ScreenManager screenManager;
        ParticleSystemCollection m_particleManager;

        public JumpNFightGame()
        {
            Window.Title = "Crate Mania";
            graphics = new GraphicsDeviceManager(this);

            // no need for antialising
            graphics.PreferMultiSampling = false;
            graphics.GraphicsProfile = GraphicsProfile.HiDef;
            graphics.SynchronizeWithVerticalRetrace = true;
            IsFixedTimeStep = false;
#if DEBUG
            graphics.PreferredBackBufferWidth = 768;
            graphics.PreferredBackBufferHeight = 512;
            graphics.IsFullScreen = false;
#else
            graphics.PreferredBackBufferWidth = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Width;
            graphics.PreferredBackBufferHeight = GraphicsAdapter.DefaultAdapter.CurrentDisplayMode.Height;
            graphics.IsFullScreen = true;
#endif
            Content.RootDirectory = "Content";

            // create the named service container
            GameServices.EnableNamedServices(this);
            // set custom viewport (harcoded to the level size 
            GameServices.Viewport = new Viewport(0, 0, 768, 512);
            GameServices.RegisterContentFolder("Content");

            // create the screen manager
            screenManager = new ScreenManager(this);
            Components.Add(screenManager);
            Services.AddService(typeof(ScreenManager), screenManager);

            audioManager = new AudioManager(this,
                "Content\\Sounds\\JumpNFight.xgs",
                "Content\\Sounds\\Music.xwb",
                "Content\\Sounds\\Waves.xwb",
                "Content\\Sounds\\Sounds.xsb");
            Services.AddService(typeof(AudioManager), audioManager);
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // add the background screen to the screen manager
            screenManager.AddScreen(new BackgroundScreen());

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            m_renderTexture = new RenderTarget2D(GraphicsDevice, GameServices.Viewport.Width, GameServices.Viewport.Height);

            // load our manifest so we know what files we have
            List<string> contentFiles = Content.Load<List<string>>("Manifest");

            // we can now see any content by finding any strings that don't have an extension
            IEnumerable<string> content = from file in contentFiles where (Path.HasExtension(file) == false && file.StartsWith("Particles/")) select file;

            // create the particle manager
            m_particleManager = new ParticleSystemCollection(this, Content, content.ToArray<string>());
            m_particleManager.Initialize();
            m_particleManager.SetViewport(GameServices.Viewport);
            Services.AddService(typeof(ParticleSystemCollection), m_particleManager);

            // load the (unique) level
            Simulation.TileMap map = GameServices.LoadContent<Simulation.TileMap>("Level1");
            map.Initialize(screenManager.Game);

            // create the world
            m_world = new Simulation.World(this, map);
            m_world.Initialize();
            // register game
            this.Services.AddService(typeof(Simulation.World), m_world);

            //
            m_world.LoadContent();

            // add the main menu screen to the screen manager
            Screens.MainMenuScreen mainScreen = new Screens.MainMenuScreen();            
            screenManager.AddScreen(mainScreen);
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // update eventing system
            GameServices.EventDispatcher.Update(gameTime);
            //
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(m_renderTexture);
            GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);

            GraphicsDevice.SetRenderTarget(null);
            // actual screen size
            Viewport vport = GraphicsDevice.Viewport;

            GraphicsDevice.Clear(Color.Black);
            spriteBatch.Begin(SpriteSortMode.Immediate,BlendState.Opaque,SamplerState.PointClamp,DepthStencilState.Default,RasterizerState.CullNone);
            bool isWideScreen = vport.Width > vport.Height;
            int width = vport.Width;
            int height = vport.Height;
            int widthOffset = 0;
            int heightOffset = 0;
            if (isWideScreen)
            {
                width = (int)(m_renderTexture.Width * vport.Height / m_renderTexture.Height);
                widthOffset = (vport.Width - width) / 2;
            }
            else
            {
                height = (int)(m_renderTexture.Height * vport.Width / m_renderTexture.Width);
                heightOffset = (vport.Height - height) / 2;
            }
            
            spriteBatch.Draw(m_renderTexture, new Rectangle(widthOffset + (int)m_world.ShakeForce.X, heightOffset + (int)m_world.ShakeForce.Y, width, height), Color.White);
            spriteBatch.End();
        }
    }
}
